/****************************************************************
 *  This file created by writerB.php on 03/26/2007 at 16:01:34  *
 ****************************************************************
 *  writerB.php created by Tonk (tonk@ctonk.com) in 2007        *
 ****************************************************************
 *                 General Document Information
 *
 *  File Name: timer.cpp
 *  Class Name: Timer
 *  Data members: 4
 *  Notes:
 ****************************************************************/

#include <iostream>
#include <sys/time.h>
#include <time.h>
#include "definitions.h"
#include "log.h"
#include "timer.h"
#include "timestamp.h"
#include "stringutil.h"
#include "world.h"



int Timer::numTimers = 0;
int Timer::timerIndex = 0;


// Default constructor...
Timer::Timer() {
	setTimerID( ++timerIndex );
	setEnabled( false );
	setInterval( 0 );
	// Increment the object count...
	numTimers++;
}

// Additional constructors...

// Copy constructor (Doesn't change _TimerID)...
Timer::Timer( const Timer& ref ) {
	setTimerID( ++timerIndex );
	setName( ref.getName() );
	setEnabled( ref.getEnabled() );
	setInterval( ref.getInterval() );
	setWhen( ref.getWhen() );
	// Increment the object count...
	numTimers++;
}

// Destructor...
Timer::~Timer() {
	// Decrement the object count...
	numTimers--;
}

// Assignment operator (Doesn't change _TimerID)...
Timer& Timer::operator = ( const Timer& ref ) {
	setName( ref.getName() );
	setEnabled( ref.getEnabled() );
	setInterval( ref.getInterval() );
	setWhen( ref.getWhen() );
	return *this;
}

// Equality operator (Doesn't compare _TimerID)...
bool Timer::operator == ( const Timer& ref ) const {
	return	(
		   getName() == ref.getName()
		&& getEnabled() == ref.getEnabled()
		&& getInterval() == ref.getInterval()
		&& getWhen() == ref.getWhen()
		);
}

// Less than operator (Compares _TimerID)...
bool Timer::operator < ( const Timer& ref ) const {
	return ( getTimerID() < ref.getTimerID() );
}

// Greater than operator (Compares _TimerID)...
bool Timer::operator > ( const Timer& ref ) const {
	return ( getTimerID() > ref.getTimerID() );
}

// Protected Methods...
void Timer::setTimerID( const int& TimerID ) { // protected
	_TimerID = TimerID;
}

void Timer::reset( void ) { // protected
	time_t current;
	time( &current );
	setWhen( current + (time_t)getInterval() );
	return;
}

void Timer::reset( unsigned long int a ) { // protected
	time_t current;
	time( &current );
	setWhen( current + (time_t)a );
	return;
}

void Timer::reset( unsigned long int a, unsigned long int b ) { // protected
	time_t current;
	time( &current );
	setWhen( current + (time_t)Timestamp::Instance().random( a, b ) );
	return;
}

// Public accessor methods...
int Timer::getTimerID( void ) const { // public
	return _TimerID;
}

void Timer::setName( const std::string& name ) { // public
	_name = name;
	return;
}

std::string Timer::getName( void ) const { // public
	return _name;
}

void Timer::setEnabled( const bool& enabled ) { // public
	_enabled = enabled;
	return;
}

bool Timer::getEnabled( void ) const { // public
	return _enabled;
}

void Timer::setInterval( const unsigned long& interval ) { // public
	_interval = interval;
	return;
}

unsigned long Timer::getInterval( void ) const { // public
	return _interval;
}

void Timer::setWhen( const time_t& when ) { // public
	_when = when;
	return;
}

time_t Timer::getWhen( void ) const { // public
	return _when;
}

// General methods...
bool Timer::fire() { // public
	time_t current;
	time( &current );

	if ( getWhen() <= current ) {
		if ( getEnabled() ) {
			return execute();
		} else {
			return false;
		}
	} else
		return true;

	return false; // fire() shouldn't ever get this far.
}

// Static methods...

// Associated operators...
std::ostream& operator << ( std::ostream& out, const Timer& timer ) { // associated
	out << &timer; // Just use the pointer version of the overloaded operator <<
	return out;
}

std::ostream& operator << ( std::ostream& out, const Timer* timer ) { // associated
	out << "TimerID:\t" << timer->getTimerID() << "\n";
	out << "name:\t" << timer->getName() << "\n";
	out << "enabled:\t" << timer->getEnabled() << "\n";
	out << "interval:\t" << timer->getInterval() << "\n";
	out << "when:\t" << timer->getWhen() << "\n";
	return out;
}

//////////////////////// tick //////////////////////////
Tick::Tick() {
	setName( "tick" );
	setEnabled( true );
	setInterval( 60 );
	reset( LOWER_TICK, UPPER_TICK );
}

Tick::~Tick() { }

bool Tick::execute() {
	std::string buf;
	std::string message;
	time_t current;
	time( &current );

	// Check for areas that need to be reset...
	for ( std::map<std::string,Area*>::iterator it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); it++ )
		if ( (*it).second->getNextReset() <= current ) {
			(*it).second->reset();
			buf << "\n\r\tArea \"" << (*it).second->getName() << "\" reset.";
		}

	// Send the tick over omninet...
	message << " {W>{C>{c>{x Tick @ " << Timestamp::Instance().getDateTime();
	for ( std::map<std::string,Character*>::iterator it = World::Instance().getCharacters().begin(); it != World::Instance().getCharacters().end(); it++ )
		if ( (*it).second->getOmninet( OMNINET_TICK ) )
			(*it).second->Send( message );

	reset( LOWER_TICK, UPPER_TICK );

	return true;
}

//////////////////////// autosave //////////////////////////
Autosave::Autosave() {
	setName( "autosave" );
	setEnabled( true );
	setInterval( 900 );
	reset();
}

Autosave::~Autosave() { }

bool Autosave::execute() {
	std::string buf;
	std::string message;
	time_t current;
	time( &current );

	// Save stuff...
	World::Instance().save();

	World::Instance().omninet( "Autosave @ " + Timestamp::Instance().getDateTime() );
	log( "Autosave.", SERVER );
	log( "Autosave.", WORLD, false );

	reset();

	return true;
}

//////////////////////// autobackup //////////////////////////
Autobackup::Autobackup() {
	setName( "autobackup" );
	setEnabled( true );
	setInterval( 86400 );
	reset();
}

Autobackup::~Autobackup() { }

bool Autobackup::execute() {
	std::string file;
	std::string command;
	std::string command2;
	std::string stamp;
	std::string buf;

	// Archive system data...
	stamp = Timestamp::Instance().backupTime();
	file << "backups/backup_" << stamp << ".tar.gz";
	command << "tar -cf " << file << " system log";
	system( command.c_str() );

	// Set permissions...
	command2 << "chmod -Rf 700 backups";
	system( command2.c_str() );

	buf << "Autobackup @ " << Timestamp::Instance().getDateTime();
	World::Instance().omninet( buf );
	log( "Autobackup.", SERVER );

	reset();

	return true;
}

//////////////////////// autoreboot //////////////////////////
Autoreboot::Autoreboot() {
	setName( "autoreboot" );
	setEnabled( true );
	setInterval( 604800 ); // Seven days
	_stage = FIVE;
	_fiveMinuteWarning = 0;
	_thirtySecondWarning = 0;
	_countdownThree = 0;
	_countdownTwo = 0;
	_countdownOne = 0;
	_countdownOver = 0;
	setWarningTimers();
}

Autoreboot::~Autoreboot() { }

void Autoreboot::setWarningTimers() { // private
	time_t current;
	time( &current );

	// Set initial _when value to a five minute warning.
	_fiveMinuteWarning = current + (time_t)_interval - (time_t)300;
	_thirtySecondWarning = current + (time_t)_interval - (time_t)30;
	_countdownThree = current + (time_t)_interval - (time_t)3;
	_countdownTwo = current + (time_t)_interval - (time_t)2;
	_countdownOne = current + (time_t)_interval - (time_t)1;
	_countdownOver = current + (time_t)_interval;
	_when = _fiveMinuteWarning;

	return;
}

bool Autoreboot::execute() {
	std::string buf;
	std::string message;
	time_t current;
	time( &current );

	switch ( _stage ) {
		case FIVE:
			log( "5 minutes until autoreboot.", SERVER );
			World::Instance().broadcast( "5 minutes until automated system reboot." );
			_when = _thirtySecondWarning;
			break;
		case THIRTY:
			log( "30 seconds until autoreboot.", SERVER );
			World::Instance().broadcast( "30 seconds until automated system reboot." );
			_when = _countdownThree;
			break;
		case THREE:
			log( "3 seconds until autoreboot.", SERVER );
			World::Instance().broadcast( "3 seconds until automated system reboot." );
			_when = _countdownTwo;
			break;
		case TWO:
			log( "2 seconds until autoreboot.", SERVER );
			World::Instance().broadcast( "2 seconds until automated system reboot." );
			_when = _countdownOne;
			break;
		case ONE:
			log( "1 second until autoreboot.", SERVER );
			World::Instance().broadcast( "1 second until automated system reboot." );
			_when = _countdownOver;
			break;
		case REBOOT:
			log( "Autoreboot...", SERVER );
			World::Instance().broadcast( "Automated system reboot..." );
			World::Instance().copyover();
			break;
		default:
			message << "Autoreboot::execute() hit default in " << __FILE__ << " line " << __LINE__;
			log( message, SERVER );
			message << "\n\t-> Autoreboot aborted.  Contact system administrator.";
			World::Instance().omninet( message );
			break;
	}

	_stage++;

	return true;
}
